import { CONFIG } from '../config.js';
import { tushareProvider } from '../providers/tushare.js';
import { applyQfq } from '../services/adjust.js';
import { interpolateGaps } from '../services/interpolate.js';
import { attachMetrics } from '../services/metrics.js';
import { getFiveYearsAgoYmd, getTodayYmd, sortByTradeDate } from '../utils/date.js';
import { logInfo, logError, logProgress } from '../utils/log.js';
import { readBundle, writeBundle, mergeSeries, loadAllHistory } from '../store/fileStore.js';
import type { DataBundle, SeriesRow, SymbolMeta } from '../shared/types.js';

function chunk<T>(arr: T[], size: number): T[][] { const out: T[][] = []; for (let i = 0; i < arr.length; i += size) out.push(arr.slice(i, i + size)); return out; }

export async function ingestInit(): Promise<void> {
  const start = getFiveYearsAgoYmd();
  const end = getTodayYmd();
  logInfo('ingest', `Init ingest from ${start} to ${end}`);
  const tickers: SymbolMeta[] = await tushareProvider.fetchTickers();
  for (const group of chunk(tickers, CONFIG.TUSHARE.BATCH_SIZE)) {
    await Promise.all(group.map(async (meta) => {
      try {
        logProgress('ingest', `init ${meta.ts_code} start`);
        const raw = await tushareProvider.fetchDaily(meta.ts_code, start, end);
        const adjFactor = await tushareProvider.fetchAdjFactor(meta.ts_code, start, end);
        let series: SeriesRow[] = applyQfq(raw, adjFactor);
        series = sortByTradeDate(series);
        series = interpolateGaps(series, 5);
        series = attachMetrics(series, 252);
        const bundle: DataBundle = {
          meta,
          series,
          summary: {
            latest_date: series[series.length - 1]?.trade_date || end,
            highest_price_prefix: Math.max(...series.map(s => s.high)),
            lowest_price_prefix: Math.min(...series.map(s => s.low)),
            currency: 'CNY', adjusted: 'qfq', source: 'tushare'
          }
        };
        await writeBundle(meta.ts_code, bundle);
        logProgress('ingest', `init ${meta.ts_code} done (${series.length} rows)`);
      } catch (e: any) {
        logError('ingest', `init ${meta.ts_code} error: ${e?.message || e}`);
      }
    }));
  }
  logInfo('ingest', 'Init ingest completed');
}

export async function ingestUpdate(): Promise<void> {
  const end = getTodayYmd();
  logInfo('ingest', `Daily update until ${end}`);
  const tickers: SymbolMeta[] = await tushareProvider.fetchTickers();
  for (const meta of tickers) {
    try {
      logProgress('ingest', `update ${meta.ts_code} start`);
      const existing = await readBundle(meta.ts_code).catch(() => null);
      const start = existing?.summary.latest_date || getFiveYearsAgoYmd();
      const raw = await tushareProvider.fetchDaily(meta.ts_code, start, end);
      const adjFactor = await tushareProvider.fetchAdjFactor(meta.ts_code, start, end);
      let series: SeriesRow[] = applyQfq(raw, adjFactor);
      series = sortByTradeDate(series);
      series = interpolateGaps(series, 5);
      series = attachMetrics(series, 14, 20, 252);
      const merged = existing ? mergeSeries(existing.series, series) : series;
      const bundle: DataBundle = {
        meta,
        series: merged,
        summary: {
          latest_date: merged[merged.length - 1]?.trade_date || end,
          highest_price_prefix: Math.max(...merged.map(s => s.high)),
          lowest_price_prefix: Math.min(...merged.map(s => s.low)),
          currency: 'CNY', adjusted: 'qfq', source: 'tushare'
        }
      };
      await writeBundle(meta.ts_code, bundle);
      logProgress('ingest', `update ${meta.ts_code} done (+${series.length} new rows)`);
    } catch (e: any) {
      logError('ingest', `update ${meta.ts_code} error: ${e?.message || e}`);
    }
  }
  logInfo('ingest', 'Daily update completed');
}

// 断点续传：根据已存在的 active 文件与日志，自动跳过已完成的 ts_code
export async function resumeInitIfNeeded(): Promise<void> {
  const start = getFiveYearsAgoYmd();
  const end = getTodayYmd();
  logInfo('ingest', `Resume init from ${start} to ${end}`);
  const all = await tushareProvider.fetchTickers();
  for (const meta of all) {
    const existing = await readBundle(meta.ts_code).catch(() => null);
    if (existing && existing.series.length) { continue; }
    try {
      const raw = await tushareProvider.fetchDaily(meta.ts_code, start, end);
      const adjFactor = await tushareProvider.fetchAdjFactor(meta.ts_code, start, end);
      let series: SeriesRow[] = applyQfq(raw, adjFactor);
      series = sortByTradeDate(series);
      series = interpolateGaps(series, 5);
      series = attachMetrics(series, 14, 20, 252);
      const bundle: DataBundle = {
        meta,
        series,
        summary: {
          latest_date: series[series.length - 1]?.trade_date || end,
          highest_price_prefix: Math.max(...series.map(s => s.high)),
          lowest_price_prefix: Math.min(...series.map(s => s.low)),
          currency: 'CNY', adjusted: 'qfq', source: 'tushare'
        }
      };
      await writeBundle(meta.ts_code, bundle);
      logProgress('ingest', `resume ${meta.ts_code} done (${series.length} rows)`);
    } catch (e: any) {
      logError('ingest', `resume ${meta.ts_code} error: ${e?.message || e}`);
    }
  }
  logInfo('ingest', 'Resume init completed');
}